package com.microcore.c2java;

import cn.hutool.core.io.FileUtil;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

enum DA_TrackMode {
    STrack,
    XTrack,
    Others;

    public static DA_TrackMode forValue(int value) {
        return values()[value];
    }

    public int getValue() {
        return this.ordinal();
    }
}

/**
 * @author FengJie
 * @date 2018/7/24
 */
public class DA_TrackPoint {
    Date dtTrackTime = new java.util.Date(0);
    double dfAzimuth;
    double dfElevation;
    DA_TrackMode emTrackMode = DA_TrackMode.forValue(0);

    public DA_TrackPoint clone() {
        DA_TrackPoint varCopy = new DA_TrackPoint();

        varCopy.dtTrackTime = this.dtTrackTime;
        varCopy.dfAzimuth = this.dfAzimuth;
        varCopy.dfElevation = this.dfElevation;
        varCopy.emTrackMode = this.emTrackMode;

        return varCopy;
    }
}

class CalTrkPrecision {
    //X频段平滑点数
    private static final int CONST_XCalNum = 100;
    //S频段平滑点数
    private static final int CONST_SCalNum = 100;
    //计算阶数
    private static final int CONST_CAL = 3;
    private List<DA_TrackPoint> m_lstTrackPoint = new ArrayList<>();
    private List<DA_TrackPoint> m_lstSelTrkPoint = new ArrayList<>();
    private String m_strFileName = "";
    private double m_dfTopEL = 0;

    public final double getTopEL() {
        return m_dfTopEL;
    }

    public final void setTopEL(double value) {
        m_dfTopEL = value;
    }

    //跟踪精度计算
    private int combination(int p, int j) {
        if (j < 0 || p < 0 || p < j) {
            return -1;
        }
        int k;
        int plus1, plus2, plus3;

        plus1 = 1;
        for (k = 1; k <= p; k++) {
            plus1 = plus1 * k;
        }

        if (j == 0) {
            plus2 = 1;
        } else {
            plus2 = 1;
            for (k = 1; k <= j; k++) {
                plus2 = plus2 * k;
            }
        }

        if (p == j) {
            plus3 = 1;
        } else {
            plus3 = 1;
            for (k = 1; k <= p - j; k++) {
                plus3 = plus3 * k;
            }
        }
        int ret;
        ret = plus1 / (plus2 * plus3);
        return ret;
    }

    //方位精度
    private double sigmaAZ(int p, int num) {
        double fSum;
        double i1, i2, i3;
        int k;
        i1 = 1;
        for (k = 1; k <= p; k++) //p的阶乘
        {
            i1 *= k;
        }
        i2 = Math.pow(i1, 2); //p的阶乘的平方
        i3 = 1;
        for (k = 1; k <= 2 * p; k++) //2p的阶乘
        {
            i3 *= k;
        }
        fSum = (((i2 / i3) * sumAZ(p, num)) / (num - p));
        return fSum;
    }

    //俯仰精度
    private double sigmaEL(int p, int num) {
        double fSum;
        double i1, i2, i3;
        int k;
        i1 = 1;
        for (k = 1; k <= p; k++) {
            i1 *= k;
        }
        i2 = Math.pow(i1, 2); //p的阶乘的平方
        i3 = 1;
        for (k = 1; k <= 2 * p; k++) //2p的阶乘
        {
            i3 *= k;
        }
        fSum = ((i2 / i3) * sumEL(p, num) / (num - p));
        return fSum;
    }

    /////////////////////////////////////
    //第一类求和
    //p:差分阶数
    //i:当前点的位置
    //DataType:数据类型
    /////////////////////////////////////////////////
    private double sum1(int p, int i, int DataType) {
        int k;
        double f1, fSum;
        if (DataType == 1) //方位角度
        {
            fSum = 0.0f;
            for (k = 0; k <= p; k++) {
                f1 = Math.pow(-1, k) * combination(p, k) * m_lstSelTrkPoint.get(i + k).dfAzimuth;
                fSum += f1;
            }
        } else if (DataType == 2) //俯仰角度
        {
            fSum = 0.0f;
            for (k = 0; k <= p; k++) {
                f1 = Math.pow(-1, k) * combination(p, k) * m_lstSelTrkPoint.get(i + k).dfElevation;
                fSum += f1;
            }
        } else {
            return -1;
        }
        return fSum;
    }

    //方位求和
    private double sumAZ(int p, int num) {
        double fSum;
        double f1, f2;
        double fcos;
        int k;
        fSum = 0.0f;
        for (k = 1; k < num - p; k++) {
            f1 = sum1(p, k, 1);
            fcos = Math.cos((m_lstSelTrkPoint.get(k).dfElevation * Math.PI) / 180.0f);
            f2 = Math.pow(f1 * fcos, 2);
            //f2=pow((f1*cos((m_measured[k].el*PI)/180.0f)),2);
            fSum += f2;
        }
        return fSum;
    }

    //俯仰求和
    private double sumEL(int p, int num) {
        double fSum;
        double f1, f2;
        int k;
        fSum = 0.0f;
        for (k = 1; k < num - p; k++) {
            f1 = sum1(p, k, 2);
            f2 = Math.pow(f1, 2);
            fSum += f2;
        }
        return fSum;
    }

    public void calTrkPrecision(String strFileNmae) {
        m_strFileName = strFileNmae;
        loadFile();
    }

    private void loadFile() {
        try {
            if (!FileUtil.exist(m_strFileName)) {
                return;
            } else {
                FileInputStream fileInputStream = new FileInputStream(new File(m_strFileName));
                InputStreamReader isr = new InputStreamReader(fileInputStream);
                BufferedReader reader = new BufferedReader(isr);
                try {
                    String line;
                    int iLineCnt = 0;
                    //char[] separator = new char[]{' ', '\t'};
                    String separator = " \t";
                    boolean bSkipFistLine = true;

                    while ((line = reader.readLine()) != null) {
                        if (bSkipFistLine && iLineCnt == 0) {
                            iLineCnt++;
                            continue;
                        }
                        try {
                            String[] split = line.split(separator);
                            DA_TrackPoint trackPoint = new DA_TrackPoint();

                            trackPoint.dtTrackTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.fff").parse(split[0] + " " + split[1]);
                            trackPoint.dfAzimuth = Double.parseDouble(split[2]);
                            trackPoint.dfElevation = Double.parseDouble(split[3]);

                            if (trackPoint.dfElevation > m_dfTopEL) {
                                m_dfTopEL = trackPoint.dfElevation;
                            }

                            if (split[7].equals("S自跟")) {
                                trackPoint.emTrackMode = DA_TrackMode.STrack;
                            } else if (split[7].equals("X自跟")) {
                                trackPoint.emTrackMode = DA_TrackMode.XTrack;
                            } else {
                                trackPoint.emTrackMode = DA_TrackMode.Others;
                            }

                            if (trackPoint.emTrackMode != DA_TrackMode.Others) {
                                m_lstTrackPoint.add(trackPoint.clone());
                            }
                        } catch (java.lang.Exception e) {
                            continue;
                        }
                    }
                } finally {
                    reader.close();
                    isr.close();
                    fileInputStream.close();
                }
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }

    public final double calPre(DA_TrackMode trkMode) {
        try {
            m_lstSelTrkPoint.clear();
            double dfElAngle = 0;
            int CalPointNum = 30;

            DA_TrackMode emMode = trkMode;

            if (emMode == DA_TrackMode.STrack) {
                CalPointNum = CONST_SCalNum;
            } else {
                CalPointNum = CONST_XCalNum;
            }

            for (int i = 0; i < m_lstTrackPoint.size(); i++) {
                if (m_lstTrackPoint.get(i).dfElevation > dfElAngle) {
                    dfElAngle = m_lstTrackPoint.get(i).dfElevation;
                }
            }

            for (int iIndex = 0; iIndex < m_lstTrackPoint.size(); iIndex++) {
                if (m_lstTrackPoint.get(iIndex).emTrackMode == emMode) {
                    if (m_lstTrackPoint.get(iIndex).dfAzimuth < 10 || m_lstTrackPoint.get(iIndex).dfAzimuth > 350) {
                        m_lstSelTrkPoint.clear();
                    } else {
                        m_lstSelTrkPoint.add(m_lstTrackPoint.get(iIndex).clone());
                    }
                }

                if (m_lstSelTrkPoint.size() >= CalPointNum) {
                    break;
                }
            }
            if (m_lstSelTrkPoint.size() > 0) {
                double fAZ = Math.sqrt(sigmaAZ(CONST_CAL, CalPointNum));
                double fEL = Math.sqrt(sigmaEL(CONST_CAL, CalPointNum));
                double sigma = Math.sqrt(fAZ * fAZ + fEL * fEL);
                //txtAzPre.Text = fAZ.ToString("f6");
                //txtElPre.Text = fEL.ToString("f6");
                return sigma;
            } else {
                return -1;
            }
            //txtSumPre.Text = sigma.ToString("f6");
        } catch (Exception e) {
            return -1;
        }
    }


}
